﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;

using GraphSharp;
using GraphSharp.Algorithms.Layout.Simple.Tree;
using GraphSharp.Algorithms.OverlapRemoval;

namespace TreeLayoutPlayground
{
    class GraphSharpLayoutEngine : LayoutEngine
    {
        public override void Layout(Tree tree)
        {
            HierarchicalGraph<Tree, TypedEdge<Tree>> graph = new HierarchicalGraph<Tree, TypedEdge<Tree>>();
            Dictionary<Tree, Point> positions = new Dictionary<Tree, Point>();
            Dictionary<Tree, Size> sizes = new Dictionary<Tree, Size>();

            Queue<Tree> work = new Queue<Tree>();
            work.Enqueue(tree);
            do
            {
                Tree cur = work.Dequeue();
                graph.AddVertex(cur);
                positions[cur] = new Point(0, 0);
                sizes[cur] = new Size(cur.MyBox.Width, cur.MyBox.Height);

                foreach (Tree c in cur.Children)
                {
                    work.Enqueue(c);
                }
            } while (work.Count > 0);

            work.Enqueue(tree);
            do
            {
                Tree cur = work.Dequeue();
                graph.AddVertex(cur);

                foreach (Tree c in cur.Children)
                {
                    graph.AddEdge(new TypedEdge<Tree>(cur, c, EdgeTypes.Hierarchical));
                    work.Enqueue(c);
                }
            } while (work.Count > 0);

            SimpleTreeLayoutParameters pars = new SimpleTreeLayoutParameters();
            pars.Direction = GraphSharp.Algorithms.Layout.LayoutDirection.TopToBottom;
            pars.OptimizeWidthAndHeight = true;
            pars.LayerGap = GapSize;
            pars.VertexGap = GapSize;
            pars.SpanningTreeGeneration = SpanningTreeGeneration.BFS;
            var layout = new SimpleTreeLayoutAlgorithm<Tree, TypedEdge<Tree>, HierarchicalGraph<Tree, TypedEdge<Tree>>>(graph, positions, sizes, pars);
            
            layout.Compute();

            int topmost = int.MaxValue;
            int leftmost = int.MaxValue;
            foreach (KeyValuePair<Tree, Point> kvp in layout.VertexPositions)
            {
                Tree t = kvp.Key;
                Point p = kvp.Value;

                t.MyBox.X = (int)p.X;
                t.MyBox.Y = (int)p.Y;

                topmost = Math.Min(topmost, t.MyBox.Y);
                leftmost = Math.Min(leftmost, t.MyBox.X);

                t.MyRelativeTranslation = System.Drawing.Size.Empty;
            }

            Dictionary<Tree, Rect> rects = new Dictionary<Tree, Rect>();
            foreach (Tree t in graph.Vertices)
            {
                t.MyBox.Offset(1 - leftmost, 1 - topmost);

                rects[t] = new Rect(t.MyBox.X, t.MyBox.Y, t.MyBox.Width, t.MyBox.Height);
            }

            OverlapRemovalParameters opars = new OverlapRemovalParameters();
            opars.HorizontalGap = GapSize;
            opars.VerticalGap = GapSize;
            var overlap = new FSAAlgorithm<Tree>(rects, opars);

            overlap.Compute();

            int botmost = 0;
            int rightmost = 0;
            
            foreach (KeyValuePair<Tree, Rect> kvp in overlap.Rectangles)
            {
                Tree t = kvp.Key;
                Rect r = kvp.Value;

                t.MyBox.X = (int)r.Left;
                t.MyBox.Y = (int)r.Top;

                botmost = Math.Max(botmost, t.MyBox.Bottom);
                rightmost = Math.Max(rightmost, t.MyBox.Right);
            }

            tree.OverallSize = new System.Drawing.Size(rightmost + 1, botmost + 1);
        }
    }
}
